package org.agilelang.fgl.parser;

/*
 AgileLang - A fourth generation language(http://www.agilelang.org).

 Copyright (C) 2013 Roderick Cusirramos (roderick20@hotmail.com)

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

import org.agilelang.object.attributes.Attribute;
import org.agilelang.object.attributes.Reference;
import org.agilelang.object.Model;
import java.util.*;
import org.agilelang.object.attributes.AttributeVirtual;


public class ModelProcess extends Process {

    private Class model_class;
    private Class attr_class;
    private Class attr_vir_class;
    private Class ref_class;
    private HashMap appModel;

    public ModelProcess() {
        try {
            model_class = Class.forName("org.agilelang.object.Model");
            attr_class = Class.forName("org.agilelang.object.attributes.Attribute");
            ref_class = Class.forName("org.agilelang.object.attributes.Reference");
            attr_vir_class = Class.forName("org.agilelang.object.attributes.AttributeVirtual");
            appModel = new HashMap();
        } catch (ClassNotFoundException ex) {
            this.error = "Error  : " + ex.toString();
        }
    }

    public boolean process(String aLine) {
        this.error = "";
        Attribute attr = new Attribute();
        AttributeVirtual attr_vir = new AttributeVirtual();
        Reference ref = new Reference();
        Model model;
        String name_model = this.setSingularize(aLine);
        if (this.isReservedWord(name_model.toLowerCase())) {
            this.error = "Error nombre es palabra reservada  : " + name_model;
            return false;
        }
        if (appModel.containsKey(name_model)) {
            model = (Model) appModel.get(name_model);
        } else {
            model = new Model();
            model.name = name_model;
            model.table = this.setPluralizeNaked(name_model).toLowerCase();
        }
        Function function = Util.getFunction(aLine);

        if (function.name.equals("define")) {
            String[] param = Util.split(function.val, ",");
            for (int i = 0; i < param.length; i++) {
                String[] paramdel = Util.split(param[i], "=");
                String name = paramdel[0];
                String value = paramdel[1].substring(1, paramdel[1].length() - 1);
                if (Util.setField(model_class, name, model, value)) {
                    appModel.put(model.name, model);
                } else {
                    this.error = "Error parametro de la funcion \"define\" no existe : " + name;
                    return false;
                }
            }
        } else if (function.name.equals("addAttribute")) {
            String[] param = Util.split_comas(function.val);
            for (int i = 0; i < param.length; i++) {
                String[] paramdel = Util.split(param[i], "=");
                String name = paramdel[0];
                String value = paramdel[1].substring(1, paramdel[1].length() - 1);
                if (name.equals("name")) {
                    if (this.isReservedWord(value)) {
                        this.error = "Error \"name\" es palabra reservada \"addAttribute\" : " + value;
                        return false;
                    }
                }
                if (name.equals("type")) {
                    if (!this.isDataType(value)) {
                        this.error = "Error en \"type\" \"addAttribute\" no existe : " + value;
                        return false;
                    }
                }
                if (!Util.setField(attr_class, name, attr, value)) {
                    this.error = "Error parametro de la funcion \"addAttribute\" no existe : " + name;
                    return false;
                }
            }
            Object arglist[] = new Object[1];
            arglist[0] = attr;
            Util.setMethod(attr, model_class, model, "addAttribute");
            appModel.put(model.name, model);
            return true;
        } else if (function.name.equals("addAttributeVirtual")) {
            String[] param = Util.split_comas(function.val);
            for (int i = 0; i < param.length; i++) {
                String[] paramdel = Util.split(param[i], "=");
                String name = paramdel[0];
                String value = paramdel[1].substring(1, paramdel[1].length() - 1);
                if (name.equals("name")) {
                    if (this.isReservedWord(value)) {
                        this.error = "Error \"name\" es palabra reservada \"addAttribute\" : " + value;
                        return false;
                    }
                }                
                if (!Util.setField(attr_vir_class, name, attr_vir, value)) {
                    this.error = "Error parametro de la funcion \"addAttribute\" no existe : " + name;
                    return false;
                }
            }
            Object arglist[] = new Object[1];
            arglist[0] = attr_vir;
            Util.setMethod(attr_vir, model_class, model, "addAttributeVirtual");
            appModel.put(model.name, model);
            return true;
        }else if (function.name.equals("addReference")) {
            String[] param = Util.split(function.val, ",");
            for (int i = 0; i < param.length; i++) {
                String[] paramdel = Util.split(param[i], "=");
                String name = paramdel[0];
                String value = paramdel[1].substring(1, paramdel[1].length() - 1);
                if (!Util.setField(ref_class, name, ref, value)) {
                    this.error = "Error parametro de la funcion \"addReference\" no existe : " + name;
                    return false;
                }
            }
            Object arglist[] = new Object[1];
            arglist[0] = ref;
            Util.setMethod(ref, model_class, model, "addReference");
            appModel.put(model.name, model);
            return true;
        } else {
            this.error = "Error Funcion no existe : " + function.name;
            return false;
        }
        return true;
    }

    public List<Model> getListModel() {
        List<Model> listmodel = new ArrayList<Model>();
        SortedSet<String> sortedset = new TreeSet<String>(appModel.keySet());
        Iterator<String> it = sortedset.iterator();
        while (it.hasNext()) {
            Model model = (Model) appModel.get(it.next());
            listmodel.add(model);
        }
        return listmodel;
    }
}
